﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;

using SWE4.Data.EmbeddedSensorCloud.DTO.Response;

using Spire.Pdf;
using Spire.Pdf.AutomaticFields;
using Spire.Pdf.Graphics;
using Spire.Pdf.Tables;

namespace EmbeddedSensorCloud.Plugin.MicroERP
{
    public class SpirePdfService : IPdfService
    {
        #region

        private PdfDocument _Doc;
        private PdfSection _Section;

        #endregion

        #region Constructor

        public SpirePdfService()
        { }

        #endregion

        #region IPdfService

        public byte[] CreatePdf(InvoiceResponseModel invoice)
        {
            //create a pdf document.
            this._Doc = new PdfDocument();
            this._Doc.DocumentInformation.Title = "Invoice Nr.: " + invoice.Number;
            this._Doc.DocumentInformation.CreationDate = this._Doc.DocumentInformation.ModificationDate = DateTime.UtcNow;
            this._Doc.DocumentInformation.Creator = this._Doc.DocumentInformation.Producer = "MicroErpService";

            //set page margin
            PdfUnitConvertor unitConverter = new PdfUnitConvertor();
            PdfMargins margin = new PdfMargins();
            margin.Top = unitConverter.ConvertUnits(2.2f, PdfGraphicsUnit.Centimeter, PdfGraphicsUnit.Point);
            margin.Bottom = margin.Top;
            margin.Left = unitConverter.ConvertUnits(2f, PdfGraphicsUnit.Centimeter, PdfGraphicsUnit.Point);
            margin.Right = margin.Left;

            SetDocumentTemplate(PdfPageSize.A4, margin, "Invoice Nr.: " + invoice.Number);

            //create section
            this._Section = this._Doc.Sections.Add();
            this._Section.PageSettings.Size = PdfPageSize.A4;
            this._Section.PageSettings.Margins = new PdfMargins(0);

            DrawInvoice(invoice, margin);

            //save pdf file to byte array
            MemoryStream bufferStream = new MemoryStream();
            this._Doc.SaveToStream(bufferStream);
            byte[] docBytes = bufferStream.ToArray();
            this._Doc.Close();

            return docBytes;
        }

        #endregion

        private void DrawInvoice(InvoiceResponseModel invoice, PdfMargins margins)
        {
            PdfPageBase page = this._Section.Pages.Add();
            float y = DrawTitle(page, 5f, invoice, margins) + 15f;

            List<string[]> invoiceDataList = new List<string[]>();

            invoiceDataList.Add(new string[] { "Item name", "Amount", "Price", "Tax", "Sub-total" });
            invoiceDataList.AddRange(invoice.Items.Select(item =>
            {
                decimal subTotal = Math.Round(item.Amount * item.UnitPrice * (1 + item.Tax / 100), 2);
                return new string[] { item.Name, item.Amount.ToString(), item.UnitPrice.ToString(), item.Tax.ToString(".00") + "%", subTotal.ToString() + " Euro" };
            }));
            if (invoice.Items.Count() == 0)
            {
                invoiceDataList.Add(new string[] { string.Empty, string.Empty, string.Empty, string.Empty, string.Empty });
            }
            string[][] invoiceDataArray = invoiceDataList.ToArray();

            PdfTable itemTable = new PdfTable();

            PdfStringFormat columnStringFormat = new PdfStringFormat(PdfTextAlignment.Center, PdfVerticalAlignment.Middle);
            PdfCellStyle headerStyle = new PdfCellStyle()
            {
                Font = new PdfTrueTypeFont(new Font("Arial", 12f, FontStyle.Bold)),
                TextBrush = new PdfSolidBrush(Color.Black),
                BorderPen = new PdfPen(Color.Black),
                StringFormat = columnStringFormat
            };
            PdfCellStyle cellStyle = new PdfCellStyle()
            {
                Font = new PdfTrueTypeFont(new Font("Arial", 11f, FontStyle.Regular)),
                TextBrush = new PdfSolidBrush(Color.Black),
                BorderPen = new PdfPen(Color.Transparent),
                StringFormat = columnStringFormat
            };
            PdfCellStyle cellAlternateStyle = new PdfCellStyle()
            {
                Font = new PdfTrueTypeFont(new Font("Arial", 11f, FontStyle.Regular)),
                TextBrush = new PdfSolidBrush(Color.Black),
                BackgroundBrush = new PdfSolidBrush(Color.FromArgb(50, 0, 0, 0)),
                BorderPen = new PdfPen(Color.Transparent),
                StringFormat = columnStringFormat
            };
            PdfTableStyle tableStyle = new PdfTableStyle();
            tableStyle.HeaderSource = PdfHeaderSource.Rows;
            tableStyle.HeaderStyle = headerStyle;
            tableStyle.HeaderRowCount = 1;
            tableStyle.ShowHeader = true;
            tableStyle.CellPadding = 2;
            tableStyle.DefaultStyle = cellStyle;
            tableStyle.AlternateStyle = cellAlternateStyle;

            itemTable.DataSource = invoiceDataArray;
            itemTable.Style = tableStyle;

            itemTable.Draw(page, 0, y);
        }

        private float DrawTitle(PdfPageBase page, float y, InvoiceResponseModel invoice, PdfMargins margins)
        {
            PdfBrush titleBrush = new PdfSolidBrush(Color.Black);
            PdfTrueTypeFont titleFont = new PdfTrueTypeFont(new Font("Verdana", 16f, FontStyle.Bold));
            PdfTrueTypeFont sumFont = new PdfTrueTypeFont(new Font("Arial", 14f, FontStyle.Bold));
            PdfStringFormat titleStringFormat = new PdfStringFormat(PdfTextAlignment.Center);
            PdfStringFormat sumStringFormat = new PdfStringFormat(PdfTextAlignment.Left);

            string titleText = string.Format("Invoice Nr.: {0}{1}{1}Contact name: {2}", invoice.Number, Environment.NewLine, invoice.Customer.GetDisplayName());
            string sumText = string.Format("Total: {0} Euro", invoice.Sum.ToString());
            SizeF titleSize = titleFont.MeasureString(titleText, titleStringFormat);
            SizeF sumSize = sumFont.MeasureString(sumText, titleStringFormat);

            page.Canvas.DrawString(titleText, titleFont, titleBrush, page.Canvas.ClientSize.Width / 2, y, titleStringFormat);
            y += titleSize.Height + 20;
            page.Canvas.DrawString(sumText, sumFont, titleBrush, margins.Left / 2 - 10, y, sumStringFormat);
            y += sumSize.Height;

            return y;
        }

        private void SetDocumentTemplate(SizeF pageSize, PdfMargins pageMargin, string headerText)
        {
            //set left and top areas
            this._Doc.Template.Left = new PdfPageTemplateElement(pageMargin.Left, pageSize.Height);

            PdfPageTemplateElement topSpace = new PdfPageTemplateElement(pageSize.Width, pageMargin.Top);
            topSpace.Foreground = true;
            this._Doc.Template.Top = topSpace;

            //draw header
            PdfTrueTypeFont headerFont = new PdfTrueTypeFont(new Font("Arial", 9f, FontStyle.Regular));
            PdfStringFormat headerStringFormat = new PdfStringFormat(PdfTextAlignment.Center);
            SizeF headerTextSize = headerFont.MeasureString(headerText, headerStringFormat);
            float y = topSpace.Height - headerFont.Height - 1;
            PdfPen pen = new PdfPen(Color.Black, 0.75f);
            topSpace.Graphics.SetTransparency(0.5f);
            topSpace.Graphics.DrawLine(pen, pageMargin.Left, y, pageSize.Width - pageMargin.Right, y);
            y -= (headerTextSize.Height + 1);
            topSpace.Graphics.DrawString(headerText, headerFont, PdfBrushes.Black, pageSize.Width / 2, y, headerStringFormat);


            //set right and bottom area
            this._Doc.Template.Right = new PdfPageTemplateElement(pageMargin.Right, pageSize.Height);

            PdfPageTemplateElement bottomSpace = new PdfPageTemplateElement(pageSize.Width, pageMargin.Bottom);
            bottomSpace.Foreground = true;
            this._Doc.Template.Bottom = bottomSpace;

            //draw footer
            y = headerFont.Height + 1;
            bottomSpace.Graphics.SetTransparency(0.5f);
            bottomSpace.Graphics.DrawLine(pen, pageMargin.Left, y, pageSize.Width - pageMargin.Right, y++);
            PdfPageNumberField pageNumber = new PdfPageNumberField();
            PdfPageCountField pageCount = new PdfPageCountField();
            PdfCompositeField pageNumberLabel = new PdfCompositeField();
            pageNumberLabel.AutomaticFields = new PdfAutomaticField[] { pageNumber, pageCount };
            pageNumberLabel.Brush = PdfBrushes.Black;
            pageNumberLabel.Font = headerFont;
            pageNumberLabel.StringFormat = new PdfStringFormat(PdfTextAlignment.Left);
            pageNumberLabel.Text = "page {0} of {1}";
            pageNumberLabel.Draw(bottomSpace.Graphics, pageMargin.Left + 10, y);
        }
    }
}